home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / comm / term / xprz_modem_2_52.lha / Send.c < prev    next >
C/C++ Source or Header  |  1992-03-06  |  18KB  |  608 lines

  1. /**********************************************************************
  2.  * Send.c: File transmission routines for xprzmodem.library;
  3.  * Original Version 2.10, 12 February 1991, by Rick Huebner.
  4.  * Based closely on Chuck Forsberg's sz.c example ZModem code,
  5.  * but too pervasively modified to even think of detailing the changes.
  6.  * Released to the Public Domain; do as you like with this code.
  7.  *
  8.  * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
  9.  * Version 2.51 29, January 1992, RX_timout fix by John Tillema
  10.  * Version 2.52   6 March 1992, Very minor fix with compiled 020 library
  11.  *               by William M. Perkins.
  12.  *
  13.  **********************************************************************/
  14.  
  15. #include <proto/all.h>
  16. #include <exec/types.h>
  17. #include <ctype.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include "xproto.h"
  21. #include "zmodem.h"
  22. #include "xprzmodem.h"
  23.  
  24. #ifdef DEBUGLOG
  25. extern void *DebugLog;
  26. #endif
  27.  
  28. /**********************************************************
  29.  *    long XProtocolSend(struct XPR_IO *xio)
  30.  *
  31.  * Main file transmission routine; called by comm program
  32.  **********************************************************/
  33. long __saveds __asm XProtocolSend(register __a0 struct XPR_IO *xio)
  34. {
  35.    struct Vars *v;
  36.    short err;
  37.  
  38.    /* Perform common setup and initializations */
  39.    if (! (v = setup(xio)) )
  40.       return XPRS_FAILURE;
  41.  
  42. /*  was 600, set to 300 to fix so it uploads correctly */
  43.    v->Rxtimeout = 300;
  44.    v->Wantfcs32 = TRUE;
  45.    v->Rxflags = 0;
  46.  
  47.    /* Transfer the files */  
  48.    zmputs(v, "rz\r");
  49.    stohdr(v, 0L);
  50.    zshhdr(v, ZRQINIT);
  51.    sendbuf(v);
  52.    if (getzrxinit(v) == ERROR)
  53.       upderr(v, "Upload cancelled or timed out");
  54.    else
  55.       sendbatch(v);
  56.  
  57.    /* Clean up and return */
  58.    if (err = v->Errcnt)
  59.       upderr(v, "One or more files skipped due to errors");
  60.    else
  61.       updmsg(v, "Done.");
  62.    if (v->io.xpr_setserial && v->Oldstatus != -1)
  63.       (*v->io.xpr_setserial)(v->Oldstatus);
  64.    FreeMem(v->Filebuf, v->Filebufmax);
  65.    FreeMem(v, (long) sizeof(struct Vars));
  66.   
  67. #ifdef DEBUGLOG
  68.    if (DebugLog)
  69.    {
  70.       xpr_fclose(&v->io, DebugLog);
  71.       DebugLog = NULL;
  72.       }
  73. #endif
  74.    return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  75.    }    /* End of long XProtocolSend() */
  76.  
  77. /**********************************************************
  78.  *    short getzrxinit(struct Vars *v)
  79.  *
  80.  * Negotiate with receiver to start a file transfer
  81.  **********************************************************/
  82. short getzrxinit(struct Vars *v)
  83. {
  84.    short n;
  85.  
  86.    for (n = v->ErrorLimit; --n >= 0; )
  87.    {
  88.       /* Check for abort from comm program */
  89.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort)())
  90.          return ERROR;
  91.       switch (zgethdr(v))
  92.       {
  93.       case ZCHALLENGE:        /* Echo receiver's challenge number */
  94.          stohdr(v, v->Rxpos);
  95.          zshhdr(v, ZACK);
  96.          sendbuf(v);
  97.          continue;
  98.       case ZCOMMAND:          /* They didn't see our ZRQINIT; try again */
  99.          stohdr(v, 0L);
  100.          zshhdr(v, ZRQINIT);
  101.          sendbuf(v);
  102.          continue;
  103.       case ZRINIT:            /* Receiver ready; get transfer parameters */
  104.      v->Rxflags = 0xFF & v->Rxhdr[ZF0];
  105.      v->Txfcs32 = (v->Wantfcs32 && (v->Rxflags & CANFC32));
  106.          v->Rxbuflen = ((USHORT) v->Rxhdr[ZP1] << 8) | v->Rxhdr[ZP0];
  107. #ifdef DEBUGLOG
  108.          mysprintf(v->Msgbuf, "Txfcs32=%ld Rxbuflen=%ld Tframlen=%ld\n",
  109.         (long) v->Txfcs32, (long) v->Rxbuflen, (long) v->Tframlen);
  110.          dlog(v, v->Msgbuf);
  111. #endif
  112.          /* Use shortest of the two side's max frame lengths */
  113.          if (v->Tframlen && (! v->Rxbuflen || v->Tframlen < v->Rxbuflen))
  114.             v->Rxbuflen = v->Tframlen;
  115. #ifdef DEBUGLOG
  116.          mysprintf(v->Msgbuf, "Rxbuflen=%ld\n", (long) v->Rxbuflen);
  117.          dlog(v, v->Msgbuf);
  118. #endif
  119.          return OK;
  120.       case ZCAN:
  121.       case RCDO:
  122.       case TIMEOUT:
  123.          upderr(v, v->Msgbuf);
  124.          return ERROR;
  125.       case ZRQINIT:
  126.          if (v->Rxhdr[ZF0] == ZCOMMAND)
  127.         continue;
  128.          /* fallthrough... */
  129.       default:
  130.          zshhdr(v, ZNAK);
  131.          sendbuf(v);
  132.          continue;
  133.          }
  134.       }
  135.    return ERROR;
  136.    }    /* End of short getzrxinit() */
  137.  
  138. /**********************************************************
  139.  *    void sendbatch(struct Vars *v)
  140.  *
  141.  * Send a batch of files
  142.  **********************************************************/
  143. void sendbatch(struct Vars *v)
  144. {
  145.    UBYTE single, done = FALSE;
  146.    long fstate;
  147.  
  148.    /* If template routines not provided, must be single filename */
  149.    if (! v->io.xpr_ffirst || ! v->io.xpr_fnext)
  150.    {
  151.       single = TRUE;
  152.       strcpy(v->Filename, v->io.xpr_filename);
  153.       /* Else use the template routines to get the first filename */
  154.       }
  155.    else
  156.    {
  157.       single = FALSE;
  158.       fstate = (*v->io.xpr_ffirst)(v->Filename, v->io.xpr_filename);
  159.       if (! fstate)
  160.       {
  161.          upderr(v, "No files match template");
  162.          return;
  163.          }
  164.       }
  165.  
  166.    /* If using templates, keep getting names & sending until done */
  167.    while (! done)
  168.    {
  169.       if (sendone(v) == ERROR)
  170.      return;
  171.       if (single)
  172.      break;
  173.       fstate = (*v->io.xpr_fnext)(fstate, v->Filename, v->io.xpr_filename);
  174.       done = ! fstate;
  175.       }
  176.  
  177.    /* End batch and return; if we never got started, just cancel receiver */
  178.    if (v->Filcnt)
  179.       saybibi(v);
  180.    else
  181.       canit(v);
  182.    }    /* End of void sendbatch() */
  183.  
  184. /**********************************************************
  185.  *    short sendone(struct Vars *v)
  186.  *
  187.  * Send the file named in v->Filename
  188.  **********************************************************/
  189. short sendone(struct Vars *v)
  190. {
  191.    struct SetupVars *sv;
  192.  
  193. #ifdef DEBUGLOG
  194.    mysprintf(v->Msgbuf, "*** Sending %s\n", v->Filename);
  195.    dlog(v, v->Msgbuf);
  196. #endif
  197.  
  198.    /* Display name of file being sent for user */
  199.    v->xpru.xpru_updatemask = XPRU_FILENAME;
  200.    v->xpru.xpru_filename = v->Filename;
  201.    (*v->io.xpr_update)(&v->xpru);
  202.  
  203.    /* Set text/binary mode according to options before opening file */
  204.    set_textmode(v);
  205.  
  206.    /* Open the file, if possible */
  207.    if (! (v->File = bfopen(v, "r")))
  208.    {
  209.       ++v->Errcnt;
  210.       upderr(v, "Can't open file; skipping");
  211.       return OK;      /* pass over it, there may be others */
  212.       }
  213.    ++v->Filcnt;
  214.    getsystime(&v->Starttime);
  215.  
  216.    /* Kick off the file transfer */
  217.    sv = (void *) v->io.xpr_data;
  218.    switch (sendname(v))
  219.    {
  220.    case ERROR:
  221.       ++v->Errcnt;
  222.       return ERROR;
  223.    case OK:
  224.       bfclose(v);
  225.       /* File sent; if option DY, delete file after sending */
  226.       if (*sv->option_d == 'Y' && v->io.xpr_extension >= 2 && v->io.xpr_unlink)
  227.       {
  228.          updmsg(v, "Deleting file after send");
  229.          (*v->io.xpr_unlink)(v->Filename);
  230.          }
  231.       break;
  232.       }
  233.    return OK;
  234.    }    /* End of short sendone() */
  235.  
  236. /**********************************************************
  237.  *    short sendname(struct Vars *v)
  238.  *
  239.  * Build file info block consisting of file name, length,
  240.  * time, and mode
  241.  **********************************************************/
  242. short sendname(struct Vars *v)
  243. {
  244.    struct SetupVars *sv;
  245.    UBYTE *p, *q, buff [32];
  246.  
  247.    /* Initialize comm program transfer status display */
  248.    v->Fsize = (v->io.xpr_finfo) ? (*v->io.xpr_finfo)(v->Filename, 1L) : -1;
  249.    v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  250.       | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  251.       | XPRU_BYTES | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE;
  252.    v->xpru.xpru_protocol = "ZModem";
  253.    v->xpru.xpru_filesize = v->Fsize;
  254.    v->xpru.xpru_msg = (v->Lzconv == ZCNL) ? "Sending text file..." :
  255.       ( (v->Lzconv == ZCBIN) ? "Sending binary file..." : "Sending file...");
  256.    v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  257.    v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
  258.    v->xpru.xpru_bytes = v->Strtpos = 0;
  259.    update_rate(v);
  260.    (*v->io.xpr_update)(&v->xpru);
  261.  
  262.    sv = (void *) v->io.xpr_data;
  263.    if (*sv->option_s == 'Y')
  264.    {
  265.       /* If "SY" option selected, send full path */
  266.       strcpy(v->Pktbuf, v->Filename);
  267.       p = v->Pktbuf + strlen(v->Pktbuf) + 1;
  268.       }
  269.    else
  270.    {
  271.       /* else extract outgoing file name without directory path */
  272.       for (p = v->Filename, q = v->Pktbuf ; *p; ++p, ++q)
  273.          if ((*q = *p) == '/' || *q == ':')
  274.         q = v->Pktbuf - 1;
  275.       *q = '\0';
  276.       p = ++q;
  277.       }
  278.  
  279.    /* Zero out remainder of file info packet */
  280.    memset(p, 0, sizeof(v->Pktbuf) - (p - v->Pktbuf));
  281.  
  282.    /* Store file size, timestamp, and mode in info packet */
  283.    /*
  284.     * XPR spec doesn't provide a way to get the file timestamp or file mode,
  285.     * so we'll just fake it with the current time and a dummy 0.
  286.     */
  287.    stcl_o(buff, getsystime(NULL) + UnixTimeOffset);
  288.    /* amiga.lib mysprintf() can't do %lo format, so we do it the hard way */
  289.    /* Yes, octal; ZModem was originally done on Unix, and they like octal there */
  290.    mysprintf(p, "%ld %s 0", (v->Fsize < 0) ? 0L : v->Fsize,buff);
  291.  
  292.    /* Send filename packet */
  293.    return zsendfile(v, (short) (p - v->Pktbuf + strlen(p) + 1));
  294.    }    /* End of short sendname() */
  295.  
  296. /**********************************************************
  297.  *    short zsendfile(struct Vars *v, short blen)
  298.  *
  299.  * Send the filename packet and see if receiver will accept
  300.  * file
  301.  **********************************************************/
  302. short zsendfile(struct Vars *v, short blen)
  303. {
  304.    short c;
  305.  
  306.    while (TRUE)
  307.    {
  308.       v->Txhdr[ZF0] = v->Lzconv; /* Text or Binary mode; from config string */
  309.       v->Txhdr[ZF1] = LZMANAG;   /* Default file management mode */
  310.       v->Txhdr[ZF2] = LZTRANS;   /* Default file transport mode */
  311.       v->Txhdr[ZF3] = 0;
  312.       zsbhdr(v, ZFILE);
  313.       zsdata(v, blen, ZCRCW);
  314.       sendbuf(v);
  315. again:
  316.       /* Check for abort from comm program */
  317.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort)())
  318.       {
  319.          bfclose(v);
  320.          return ERROR;
  321.          }
  322.       switch (c = zgethdr(v))
  323.       {
  324.       case ZRINIT:
  325.          goto again;
  326.       case ZCAN:
  327.       case ZCRC:
  328.       case RCDO:
  329.       case TIMEOUT:
  330.       case ZABORT:
  331.       case ZFIN:
  332.          upderr(v, v->Msgbuf);
  333.          return ERROR;
  334.       case ZSKIP:             /* Receiver doesn't want this one */
  335.          upderr(v, "SKIP command received");
  336.          bfclose(v);
  337.          return c;
  338.       case ZRPOS:             /* Receiver wants it; this is starting position */
  339.          bfseek(v, v->Rxpos);
  340.          v->Strtpos = v->Txpos = v->Rxpos;
  341.          if (v->io.xpr_sflush)
  342.         (*v->io.xpr_sflush)();
  343.          v->Modemcount = 0;
  344.          return zsendfdata(v);
  345.          }
  346.       }
  347.    }    /* End of short zsendfile() */
  348.  
  349. /**********************************************************
  350.  *    short zsendfdata(struct Vars *v)
  351.  *
  352.  * Send the file data
  353.  **********************************************************/
  354. short zsendfdata(struct Vars *v)
  355. {
  356.    short c, e, blklen, goodbytes = 0;
  357.    USHORT framelen, maxblklen, goodneeded = 512;
  358.  
  359.    /* Figure out max data packet size to send */
  360.    maxblklen = KSIZE;
  361.    if (v->Rxbuflen && maxblklen > v->Rxbuflen)
  362.       maxblklen = v->Rxbuflen;
  363.    blklen = (v->Baud < 1200) ? 256 : KSIZE;
  364.    if (blklen > maxblklen)
  365.       blklen = maxblklen;
  366. #ifdef DEBUGLOG
  367.    mysprintf(v->Msgbuf, "Rxbuflen=%ld blklen=%ld\n", (long) v->Rxbuflen,
  368.       (long) blklen);
  369.    dlog(v, v->Msgbuf);
  370. #endif
  371.  
  372.    /* If an interruption happened, handle it; else keep sending data */
  373. somemore:
  374.    while (char_avail(v))
  375.    {
  376.       /* Check for another incoming packet while discarding line noise */
  377.       switch (readock(v, 1))
  378.       {
  379.       case CAN:
  380.       case RCDO:
  381.       case ZPAD:
  382.          break;
  383.       default:
  384.          continue;
  385.          }
  386. waitack:
  387. #ifdef DEBUGLOG
  388.       dlog(v, "--- At waitack\n");
  389. #endif
  390.       switch (c = getinsync(v))
  391.       {
  392.       default:
  393.          upderr(v, "Transfer cancelled");
  394.          bfclose(v);
  395.          return ERROR;
  396.       case ZSKIP:  /* Receiver changed its mind and wants to skip the file */
  397.          return c;
  398.       case ZACK:   /* ACK at end of frame; resume sending data */
  399.          break;
  400.       case ZRPOS:  /* An error; resend data from last good point */
  401.          blklen >>= 2;
  402.          if (blklen < MINBLOCK)
  403.         blklen = MINBLOCK;
  404.          if (goodneeded < MAXGOODNEEDED)
  405.         goodneeded <<= 1;
  406.          v->xpru.xpru_updatemask = XPRU_ERRORS;
  407.          ++v->xpru.xpru_errors;
  408.          (*v->io.xpr_update)(&v->xpru);
  409.          break;
  410.       case ZRINIT:
  411.          updmsg(v, "Done.");
  412.          return OK;
  413.          }
  414.       }
  415.  
  416.    /* Transmit ZDATA frame header */
  417.    framelen = v->Rxbuflen;
  418.    stohdr(v, v->Txpos);
  419.    zsbhdr(v, ZDATA);
  420.  
  421.    /* Keep sending data packets until finished or interrupted */
  422.    do
  423.    {
  424.       /* Read next chunk of file data */
  425.       c = bfread(v, v->Pktbuf, (long) blklen);
  426.  
  427.       /* Figure out how to handle this data packet */
  428.       if (c < blklen)
  429.          e = ZCRCE;  /* If end of file, this is last data packet */
  430.       else if (v->Rxbuflen && (framelen -= c) <= 0)
  431.          e = ZCRCW;  /* If end of frame, ask for ACK */
  432.       else
  433.          e = ZCRCG;  /* Else tell receiver to expect more data packets */
  434.  
  435.       zsdata(v, c, e);  /* Send the packet */
  436.       sendbuf(v);
  437.  
  438.       /* Update comm program status display */
  439.       v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  440.          | XPRU_EXPECTTIME | XPRU_ELAPSEDTIME | XPRU_DATARATE
  441.      | XPRU_BLOCKCHECK;
  442.       ++v->xpru.xpru_blocks;
  443.       v->xpru.xpru_blocksize = c;
  444.       v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
  445.       v->xpru.xpru_bytes = v->Txpos += c;
  446.       update_rate(v);
  447.       (*v->io.xpr_update)(&v->xpru);
  448.  
  449.       /*
  450.        * If we've been sending smaller than normal packets, see if it's
  451.        * time to bump the packet size up a notch yet
  452.        */
  453.       if (blklen < maxblklen && (goodbytes += c) >= goodneeded)
  454.       {
  455.          blklen <<= 1;
  456.          if (blklen > maxblklen)
  457.         blklen = maxblklen;
  458.          goodbytes = 0;
  459. #ifdef DEBUGLOG
  460.          mysprintf(v->Msgbuf, "Bumping packet size to %ld at %ld\n",
  461.         (long) blklen, v->Txpos);
  462.          dlog(v, v->Msgbuf);
  463. #endif
  464.          }
  465.  
  466.       /* Give comm program its timeslice if it needs one */
  467.       if (v->io.xpr_chkmisc)
  468.      (*v->io.xpr_chkmisc)();
  469.       /* Check for abort from comm program */
  470.       if (v->io.xpr_chkabort && (*v->io.xpr_chkabort)())
  471.      goto aborted;
  472.       /* If this was last packet in frame, go wait for ACK from receiver */
  473.       if (e == ZCRCW)
  474.      goto waitack;
  475.  
  476.       /*
  477.        * Check if receiver trying to interrupt us; look for incoming packet
  478.        * while discarding line noise
  479.        */
  480.       while (char_avail(v))
  481.       {
  482.          switch (readock(v, 1))
  483.      {
  484.          case CAN:
  485.          case RCDO:
  486.          case ZPAD:
  487.             /* Interruption detected; stop sending and process complaint */
  488. #ifdef DEBUGLOG
  489.             dlog(v, "--- Interrupted send\n");
  490. #endif
  491.             zsdata(v, 0, ZCRCE);
  492.             sendbuf(v);
  493.             goto waitack;
  494.             }
  495.          }
  496.       }
  497.    while (e == ZCRCG);  /* If no interruption, keep sending data packets */
  498.  
  499.    /* Done sending file data; send EOF and wait for receiver to acknowledge */
  500.    while (TRUE)
  501.    {
  502.       updmsg(v, "Sending EOF");
  503.       stohdr(v, v->Txpos);
  504.       zsbhdr(v, ZEOF);
  505.       sendbuf(v);
  506.       switch (c = getinsync(v))
  507.       {
  508.       case ZACK:
  509.          continue;
  510.       case ZRPOS:
  511.          goto somemore;
  512.       case ZRINIT:
  513.          updmsg(v, "EOF acknowledged");
  514.          ++v->Starttime.tv_secs;
  515.          update_rate(v);
  516.          v->xpru.xpru_updatemask = XPRU_EXPECTTIME | XPRU_ELAPSEDTIME
  517.         | XPRU_DATARATE;
  518.          (*v->io.xpr_update)(&v->xpru);
  519.          return OK;
  520.       case ZSKIP:
  521.          return c;
  522.       default:
  523. aborted:
  524.      upderr(v, "Transfer cancelled");
  525.          bfclose(v);
  526.          return ERROR;
  527.          }
  528.       }
  529.    }    /* End of short zsendfdata() */
  530.  
  531. /**********************************************************
  532.  *    short getinsync(struct Vars *v)
  533.  *
  534.  * Respond to receiver's complaint, get back in sync with
  535.  * receiver
  536.  **********************************************************/
  537. short getinsync(struct Vars *v)
  538. {
  539.    short c;
  540.  
  541.    while (TRUE)
  542.    {
  543. #ifdef DEBUGLOG
  544.       dlog(v, "--- At getinsync\n");
  545. #endif
  546.       c = zgethdr(v);
  547.       if (v->io.xpr_sflush)
  548.          (*v->io.xpr_sflush)();
  549.       v->Modemcount = 0;
  550.       switch (c)
  551.       {
  552.       case ZCAN:
  553.       case ZABORT:
  554.       case ZFIN:
  555.       case RCDO:
  556.       case TIMEOUT:
  557.          upderr(v, v->Msgbuf);
  558.          return ERROR;
  559.       case ZRPOS:
  560.          bfseek(v, v->Rxpos);
  561.          v->Txpos = v->Rxpos;
  562.          mysprintf(v->Msgbuf, "Resending from %ld", v->Txpos);
  563.          upderr(v, v->Msgbuf);
  564.          return c;
  565.       case ZSKIP:
  566.          upderr(v, "SKIP command received");
  567.          /* fallthrough... */
  568.       case ZRINIT:
  569.          bfclose(v);
  570.          /* fallthrough... */
  571.       case ZACK:
  572.          return c;
  573.       default:
  574.          zsbhdr(v, ZNAK);
  575.          sendbuf(v);
  576.          continue;
  577.          }
  578.       }
  579.    }    /* End of short getinsync() */
  580.  
  581. /**********************************************************
  582.  *    void saybibi(struct Vars *v)
  583.  *
  584.  * End of batch transmission; disengage cleanly from receiver
  585.  **********************************************************/
  586. void saybibi(struct Vars *v)
  587. {
  588.    while (TRUE)
  589.    {
  590.       stohdr(v, 0L);
  591.       zsbhdr(v, ZFIN);
  592.       sendbuf(v);
  593.       switch (zgethdr(v))
  594.       {
  595.       case ZFIN:
  596.          sendline(v, 'O');
  597.          sendline(v, 'O');
  598.          sendbuf(v);
  599.          /* fallthrough... */
  600.       case ZCAN:
  601.       case RCDO:
  602.       case TIMEOUT:
  603.          return;
  604.          }
  605.       }
  606.    }    /* End of void saybibi() */
  607. /* End of Send.c source */
  608.